Skip to content

Solari support on metal backends - #25123

Merged
alice-i-cecile merged 9 commits into
bevyengine:mainfrom
mate-h:m/solari-metal
Jul 28, 2026
Merged

alice-i-cecile merged 9 commits into
bevyengine:mainfrom
mate-h:m/solari-metal

Conversation

@mate-h

@mate-h mate-h commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Objective

Ray tracing on Metal has been available since wgpu 29.

I shipped a PR to wgpu for implementing bindless storage buffers for metal, which was released with wgpu 30. With the wgpu 30 PR in bevy merged, we are fully ready to add support to Solari on metal backends!

However because there is a limit of 31 buffer slots per shader stage. Running Solari on main on a raytracing compatible Mac results in a crash.

Solution

I had combine the world cache into a single packed buffer. In theory this should not introduce performance regressions since it’s only reorganizing bindings and doesn’t introduce and copy or other passes. Tried keeping the diff fairly minimal and easy to review.

Getting the buffer layout for the world cache on the CPU with ShaderType was tricky. To avoid blowing up memory I put it in a private module so you can't construct it.

Testing

  • Ran the Solari example on mac
cargo run --example solari --features bevy_solari,https,free_camera

Currently this PR needs a benchmark against main to ensure there's no perf regression. I could use some help with that!


Showcase

shot

Known limitations

Tracing spans incorrectly report 0.0ms , tracking in gfx-rs/wgpu#9414

No denoising support yet. Could theoretically use MetalFX Ray Reconstruction in place of DLSS for cross-platform denoising support in Solari. In the longer term we are also looking at Open Image Denoise 3.0 that promises temporal denoising support.

@mate-h
mate-h requested review from JMS55 and SparkyPotato July 22, 2026 16:38
@mate-h mate-h added A-Rendering Drawing game state to the screen S-Needs-Benchmarking This set of changes needs performance benchmarking to double-check that they help S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jul 22, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in Rendering Jul 22, 2026
@mate-h mate-h added O-Metal Specific to the Metal render API M-Release-Note Work that should be called out in the blog due to impact labels Jul 22, 2026

@stuartparmenter stuartparmenter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code changes here all seem right and make sense -- just a few mostly nits

@ChristopherBiscardi ChristopherBiscardi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solari runs on my m5 macbook pro. (note that this image is webp for size reduction reasons).

Image

Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>

@JMS55 JMS55 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functionally lgtm, and I verified it doesn't affect perf on a 5080.

Left some style comments.

Comment thread crates/bevy_solari/src/realtime/node.rs Resolved
@mate-h mate-h removed S-Needs-Benchmarking This set of changes needs performance benchmarking to double-check that they help S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jul 28, 2026
@mate-h mate-h added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Jul 28, 2026
@alice-i-cecile
alice-i-cecile added this pull request to the merge queue Jul 28, 2026
@alice-i-cecile
alice-i-cecile removed this pull request from the merge queue due to a manual request Jul 28, 2026
@alice-i-cecile
alice-i-cecile enabled auto-merge July 28, 2026 20:45
@alice-i-cecile
alice-i-cecile added this pull request to the merge queue Jul 28, 2026
Merged via the queue into bevyengine:main with commit eb07f80 Jul 28, 2026
38 checks passed
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in Rendering Jul 28, 2026
joelawm pushed a commit to joelawm/bevy that referenced this pull request Sep 8, 2026
# Objective

[Ray tracing on Metal](gfx-rs/wgpu#8071) has
been available since wgpu 29.

I shipped a PR to wgpu for [implementing bindless storage
buffers](gfx-rs/wgpu#9081) for metal, which was
released with wgpu 30. With the [wgpu 30
PR](bevyengine#24841) in bevy merged, we
are fully ready to add support to Solari on metal backends!

However because there is a limit of 31 buffer slots per shader stage.
Running Solari on main on a raytracing compatible Mac results in a
crash.

## Solution

I had combine the world cache into a single packed buffer. In theory
this should not introduce performance regressions since it’s only
reorganizing bindings and doesn’t introduce and copy or other passes.
Tried keeping the diff fairly minimal and easy to review.

Getting the buffer layout for the world cache on the CPU with
`ShaderType` was tricky. To avoid blowing up memory I put it in a
private module so you can't construct it.

## Testing

- Ran the Solari example on mac

```
cargo run --example solari --features bevy_solari,https,free_camera
```

Currently this PR needs a benchmark against main to ensure there's no
perf regression. I could use some help with that!

---

## Showcase

<img width="2566" height="1514" alt="shot"
src="https://github.com/user-attachments/assets/691b9bd3-129f-47e6-8efe-313cbadd6ff5"
/>

## Known limitations

Tracing spans incorrectly report 0.0ms , tracking in
gfx-rs/wgpu#9414

No denoising support yet. Could theoretically use [MetalFX Ray
Reconstruction](https://crates.io/crates/objc2-metal-fx) in place of
DLSS for cross-platform denoising support in Solari. In the longer term
we are also looking at Open Image Denoise 3.0 that promises temporal
denoising support.

---------

Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
ickshonpe pushed a commit to ickshonpe/bevy that referenced this pull request Sep 17, 2026
# Objective

- bevyengine#25123 introduced Solari on Metal
- bevyengine#25423 broke compatibility with Metal

It changed Solari’s motion vectors from a sampled `texture_2d<f32>` to
`texture_storage_2d<rg16float, read_write>`.

Presently on main we get a crash on Metal:
```
2026-09-14T18:43:13.274411Z ERROR bevy_render::error_handler: Caught rendering error: Validation Error

Caused by:
  In Device::create_bind_group_layout, label = 'solari_lighting_bind_group_layout'
    Binding index 5: ReadWrite access to storage textures with format Rg16Float is not supported
```

`rg16float` can't be bound as a read-write storage texture on Metal.
Vulkan and DX12 usually can.

## Solution

ReSTIR only samples motion vectors to reproject last frame's reservoir.
The only writer is DLSS Ray Reconstruction PSR, and only for perfect
mirrors — everything else already goes to `specular_motion_vectors`.

At pipeline init we check whether the adapter supports
`STORAGE_READ_WRITE` on `rg16float`. If it does, we keep the storage
binding and write PSR motion in place. If not, we sample a
`texture_2d<f32>` and skip the write. DLSS RR doesn't run on those GPUs
anyway.

## Testing

- Ran the Solari example on Metal (Apple M5), no crash
- Could not test the DLSS in-place path (no `DLSS_SDK` / NVIDIA GPU on
this machine)
- CI check for Metal + Solari is still missing (no available hw to test
on?)
gregcsokas pushed a commit to gregcsokas/bevy that referenced this pull request Sep 21, 2026
# Objective

- bevyengine#25123 introduced Solari on Metal
- bevyengine#25423 broke compatibility with Metal

It changed Solari’s motion vectors from a sampled `texture_2d<f32>` to
`texture_storage_2d<rg16float, read_write>`.

Presently on main we get a crash on Metal:
```
2026-09-14T18:43:13.274411Z ERROR bevy_render::error_handler: Caught rendering error: Validation Error

Caused by:
  In Device::create_bind_group_layout, label = 'solari_lighting_bind_group_layout'
    Binding index 5: ReadWrite access to storage textures with format Rg16Float is not supported
```

`rg16float` can't be bound as a read-write storage texture on Metal.
Vulkan and DX12 usually can.

## Solution

ReSTIR only samples motion vectors to reproject last frame's reservoir.
The only writer is DLSS Ray Reconstruction PSR, and only for perfect
mirrors — everything else already goes to `specular_motion_vectors`.

At pipeline init we check whether the adapter supports
`STORAGE_READ_WRITE` on `rg16float`. If it does, we keep the storage
binding and write PSR motion in place. If not, we sample a
`texture_2d<f32>` and skip the write. DLSS RR doesn't run on those GPUs
anyway.

## Testing

- Ran the Solari example on Metal (Apple M5), no crash
- Could not test the DLSS in-place path (no `DLSS_SDK` / NVIDIA GPU on
this machine)
- CI check for Metal + Solari is still missing (no available hw to test
on?)
mockersf pushed a commit that referenced this pull request Sep 25, 2026
# Objective

- #25123 introduced Solari on Metal
- #25423 broke compatibility with Metal

It changed Solari’s motion vectors from a sampled `texture_2d<f32>` to
`texture_storage_2d<rg16float, read_write>`.

Presently on main we get a crash on Metal:
```
2026-09-14T18:43:13.274411Z ERROR bevy_render::error_handler: Caught rendering error: Validation Error

Caused by:
  In Device::create_bind_group_layout, label = 'solari_lighting_bind_group_layout'
    Binding index 5: ReadWrite access to storage textures with format Rg16Float is not supported
```

`rg16float` can't be bound as a read-write storage texture on Metal.
Vulkan and DX12 usually can.

## Solution

ReSTIR only samples motion vectors to reproject last frame's reservoir.
The only writer is DLSS Ray Reconstruction PSR, and only for perfect
mirrors — everything else already goes to `specular_motion_vectors`.

At pipeline init we check whether the adapter supports
`STORAGE_READ_WRITE` on `rg16float`. If it does, we keep the storage
binding and write PSR motion in place. If not, we sample a
`texture_2d<f32>` and skip the write. DLSS RR doesn't run on those GPUs
anyway.

## Testing

- Ran the Solari example on Metal (Apple M5), no crash
- Could not test the DLSS in-place path (no `DLSS_SDK` / NVIDIA GPU on
this machine)
- CI check for Metal + Solari is still missing (no available hw to test
on?)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen M-Release-Note Work that should be called out in the blog due to impact O-Metal Specific to the Metal render API S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants